<?php

namespace StudyBuddy\Controllers;

use StudyBuddy\Request;

use \StudyBuddy\WebPage;
use \StudyBuddy\Paginator;
use \StudyBuddy\CacheHeaders;
use \StudyBuddy\Badwords;
use \StudyBuddy\Question;
use \StudyBuddy\Answers;
use \StudyBuddy\Template\Urhere;
use \StudyBuddy\Forms\Answerform;
use \StudyBuddy\QuestionInfo;
use \StudyBuddy\Responder;
use \StudyBuddy\SocialCheckboxes;

use \StudyBuddy\Math\Math;
/**
 * Controller for displaying
 * a Question, Answers to a question (paginated)
 * and an Answer form
 * as well as adding Question Info block
 *
 */
class Viewquestion extends WebPage
{

	protected $aRequired = array('qid');


	/**
	 * Array with question data
	 * The oQuestion is created from this array
	 * but even though we can use oQuestion to
	 * get all the data, it may be faster to
	 * get data from array, so why not have
	 * them both in this object at a tiny
	 * overhead
	 *
	 * @var array
	 */
	protected $aQuestion;

	/**
	 * Object representing the question
	 * that we currently viewing
	 *
	 * @var object of type Question
	 */
	protected $oQuestion;

	/**
	 * The "Answer" form object
	 *
	 * @var object of type Answerform which is a Form
	 */
	protected $oForm;

	protected $aTplVars = array();

	protected $pageID = 1;


	/**
	 * Flag indicates that comments have
	 * been disabled, causing a special 'nocomments' css
	 * class to be added to answer template, hiding
	 * "comments" div, which also hides the "add comments" link
	 *
	 * @var bool
	 */
	protected $noComments = false;

	/**
	 * Sort by: i_lm_ts, i_ts or i_score
	 * this value is used to generate cache headers
	 * as each sort condition generates
	 * different page content, thus should be
	 * included in generating the "etag"
	 *
	 * @var string
	 */
	protected $tab = 'i_lm_ts';

	/**
	 * html of parsed answers
	 *
	 *
	 * @var string
	 */
	protected $answers = '';


	/**
	 * Number of total answers for this question
	 *
	 *
	 * @var int
	 */
	protected $numAnswers = 0;


	/**
	 * Main entry point
	 * (non-PHPdoc)
	 * @see WebPage::main()
	 */
	protected function main(){
		if(Request::isAjax()){
			$this->getQuestion()->getAnswers();
			Responder::sendJSON(array('paginated' => $this->answers));
		}



		$this->pageID = $this->oRegistry->Request->get('pageID', 'i', 1);
		$this->tab = $this->oRegistry->Request->get('sort', 's', 'i_lm_ts');
		$this->oRegistry->registerObservers();

		$this->getQuestion()
		->addMetas()
		->sendCacheHeaders()
		->configureEditor()
		->setTitle()
		->addMetaTags()
		//->setAnswersHeader()
		->getAnswers()
		->setAnswers()
		->setSimilar()
		->makeForm()
		->setAnswerForm()
		//->makeFollowButton()
		//->setFollowersBlock()
		->makeRecentTags()
		->makeRecentActivites()
		->makeTutorListing()
		//->setQuestionInfo()
		->setFooter()
		->increaseView()
		->checkGainOtherBadges()
		->makeTopTabs();

		$this->oRegistry->Dispatcher->post($this->oQuestion, 'onQuestionView');
	}


	/**
	 * Add extra meta tags to indicate
	 * that user has or does not have
	 * blogger and tumblr Oauth keys
	 *
	 * @return object $this
	 */
	protected function addMetas(){
		$this->addMetaTag('tm', (null !== $this->oRegistry->Viewer->getTumblrToken()));
		$this->addMetaTag('blgr', (null !== $this->oRegistry->Viewer->getBloggerToken()));
		$this->addMetaTag('linkedin', (null !== $this->oRegistry->Viewer->getLinkedInToken()));
		
		return $this;
	}

	/**
	 * Adds block with info about
	 * this question to the
	 * $this->aPageVars['side']
	 *
	 * @return object $this
	 */
	protected function setQuestionInfo(){

		$this->aPageVars['side'] .= QuestionInfo::factory($this->oRegistry)->getHtml($this->oQuestion);

		return $this;
	}


	/**
	 * If this question has any followers
	 * then add block with
	 * some followers' avatars
	 *
	 * @return object $this
	 */
	protected function setFollowersBlock(){
		$aFlwrs = $this->oQuestion['a_flwrs'];
		$count = count($aFlwrs);
		if($count > 0){
			$s = \StudyBuddy\ShowFollowers::factory($this->oRegistry)->getQuestionFollowers($aFlwrs, $count);
			d('followers: '.$s);
			$this->aPageVars['side'] .= '<div class="fr cb w90 lg rounded3 pl10 mb10">'.$s.'</div>';
		}

		return $this;
	}


	/**
	 * Add meta tags 'qid' and 'lmts' for
	 * last modified timestamp
	 * The javascript will be able to query the server
	 * to check for the new answers for this qid since that lmts
	 * Some of these meta tags will be used by JavaScript
	 * to determine if viewer has permissions to comment
	 *
	 * @return object $this
	 */
	protected function addMetaTags(){
		$this->addMetaTag('lmts', $this->oQuestion['i_lm_ts']);
		$this->addMetaTag('qid', $this->oQuestion['_id']);
		$this->addMetaTag('asker_id', $this->oQuestion->getOwnerId());
		$this->addMetaTag('etag', $this->oQuestion['i_etag']);
		$this->addMetaTag('min_com_rep', \StudyBuddy\Points::COMMENT);
		$this->addMetaTag('comment', $this->oRegistry->Viewer->isAllowed('comment'));

		return $this;
	}


	/**
	 * Get array for this one question,
	 * set $this->oQuestion
	 * and also set $this->aTplVars['body']
	 * with parsed tplQuestion block
	 *
	 *
	 * @throws StudyBuddy404Exception if question not found
	 *
	 * @return object $this
	 */
	protected function getQuestion(){
		$isModerator = $this->oRegistry->Viewer->isModerator();
		$this->noComments = (false === (bool)$this->oRegistry->Ini->MAX_COMMENTS);
		d('no comments: '.$this->noComments);
		$aFields = ($this->noComments || false === (bool)$this->oRegistry->Ini->SHOW_COMMENTS) ? array('comments' => 0) : array();

		$this->aQuestion = $this->oRegistry->Mongo->QUESTIONS->findOne(array('_id' => (int)$this->oRequest['qid']), $aFields);

		/**
		 * @todo Translate string
		 */
		if(empty($this->aQuestion)){
			throw new \StudyBuddy\StudyBuddy404Exception('Question not found');
		}
		d('$this->aQuestion: '.print_r($this->aQuestion, 1));

		/**
		 * Only moderators can see ip address
		 */
		if(!$isModerator && !empty($this->aQuestion['ip'])){
			unset($this->aQuestion['ip']);
		}

		$deleted = (!empty($this->aQuestion['i_del_ts'])) ?  ' deleted' : false;

		/**
		 * Guests will have to see filtered
		 * content
		 */
                // equation
                $math = new Math();
                $this->aQuestion['b'] = $math->mathfilter($this->aQuestion['b'], 13, 'http://'.$_SERVER['HTTP_HOST'].'/w/img/equation/');
		if(!$this->isLoggedIn()){
			$this->aQuestion['b'] = Badwords::filter($this->aQuestion['b'], true);
		}

		$this->oQuestion = new Question($this->oRegistry, $this->aQuestion);

		/**
		 * @todo Translate string
		 */
		if($deleted){
			if(!$isModerator && !\StudyBuddy\isOwner($this->oRegistry->Viewer, $this->oQuestion)){
				throw new \StudyBuddy\StudyBuddy404Exception('Question was deleted on '.date('F j Y', $this->aQuestion['i_del_ts']));
			}

			/**
			 * If Viewer is moderator, then viewer
			 * will be able to view deleted item
			 * This will add 'deleted' class to question table
			 */

			$this->aQuestion['deleted'] = $deleted;
			if(!empty($this->aQuestion['a_deleted'])){
				$this->aQuestion['deletedby'] = \tplDeletedby::parse($this->aQuestion['a_deleted'], false);
				d('deletedby: '.$this->aQuestion['deletedby']);
			}
		}

		if($this->noComments){
			$this->aQuestion['nocomments'] = ' nocomments';
		}
		
		$this->aQuestion['add_comment'] = $this->_('add comment');
		$this->aQuestion['reply']       = $this->_('Reply');
		$this->aQuestion['reply_t']     = $this->_('Reply to this comment');
		$this->aQuestion['edited']      = $this->_('Edited');
                $this->aQuestion['followhtml']  = $this->makeFollowButton();

		$this->aPageVars['body'] = \tplQuestion::parse($this->aQuestion);

		return $this;
	}


	/**
	 * Create header div for answers block.
	 * This div is independant of answers
	 * block and contains word "Answers",
	 * count of answers and some 'sort by'
	 * tabs
	 *
	 * @todo translate word 'Answer'
	 *
	 * @return object $this
	 */
	protected function setAnswersHeader(){
		$tabs = '';

		/**
		 * Does not make sense to show
		 * any type of 'sort by' when there is
		 * only 1 answer or no answers at all
		 */
		if($this->oQuestion['i_ans'] > 1){
			$cond = $this->oRegistry->Request->get('sort', 's', 'i_lm_ts');
			$tabs = Urhere::factory($this->oRegistry)->get('tplAnstypes', $cond);
		}

		$aVars = array(
		$this->oQuestion['i_ans'],
		'Answer'.$this->oQuestion['ans_s'],
		$tabs
		);

		$this->aPageVars['body'] .= \tplAnswersheader::parse($aVars, false);

		return $this;
	}


	/**
	 * Set page title meta and h2 tag
	 *
	 * @return object $this
	 */
	protected function setTitle(){
		$title = $this->oQuestion['title'];
		$title = (!$this->isLoggedIn()) ? Badwords::filter($title) : $title;

		/**
		 * @todo Translate string "closed"
		 */
		if(!empty($this->aQuestion['a_closed'])){
			$title .= ' [closed]';
		}
		$this->aPageVars['title'] = $title;
		$this->aPageVars['qheader'] = '<h1>'.$title.'</h1>';

		return $this;
	}


	/**
	 * Send out HTTP Cache control Headers
	 *
	 */
	protected function sendCacheHeaders(){

		/**
		 * In case there is a login_error
		 * the user is redirected to this question
		 * via redirect header and if we don't do this check
		 * then the browser will display the cached version
		 * and user will never see login error
		 * in login form
		 */
		if(!empty($_SESSION['login_error'])){
			return $this;
		}

		$latestReplyTime = $this->oQuestion->getEtag();
		$userHash = $this->oRegistry->Viewer->hashCode();
		d('user Hash: '.$userHash);
		$etag = '"'.hash('md5', $this->oRequest['qid'].'-'.$this->pageID.$this->tab.'-'.$latestReplyTime.'-' .$userHash).'"';
		//$lastModified = gmdate("D, d M Y H:i:s", $latestReplyTime)." GMT";

		CacheHeaders::processCacheHeaders($etag); //, $lastModified

		return $this;
	}


	/**
	 * Set answers title bar with
	 * sort tags
	 * and under it add div id="answers"
	 * and insert answers html into it
	 * use Answers::get(oQuestion, $sort, $pageID)
	 * it should return html with all answers
	 *
	 * OR if there are no answers, then a text saying
	 * "Be the first to answer this question"
	 * inside a special div with special id so that
	 * when same user posts and gets json reply
	 * we can remove that special div from page
	 *
	 * @return object $this
	 *
	 */
	protected function setAnswers(){

		$tpl = '<div id="answers" class="sortable paginated fl cb w100" StudyBuddy:total="%1$s" StudyBuddy:perpage="%2$s">%3$s</div><!-- // answers -->';
		$this->aPageVars['body'] .= vsprintf($tpl, array($this->numAnswers, $this->oRegistry->Ini->PER_PAGE_ANSWERS, $this->answers));

		return $this;
	}


	/**
	 * Uses the Answers class to get the
	 * block of parsed answers (in html)
	 * It will automatically apply pagination if necessary,
	 * add pagination links and return the content of just one page
	 * of answers. It's just that smart!
	 *
	 * Sets values of $this->answers
	 * and $this->numAnswers
	 *
	 * @return object $this
	 */
	protected function getAnswers(){
		$this->answers = '';
		$this->numAnswers = $this->oQuestion['i_ans'];
		if($this->numAnswers > 0 || $this->oRegistry->Viewer->isModerator()){
			$this->answers = Answers::factory($this->oRegistry)->getAnswers($this->oQuestion);
		}

		/**
		 * Every page with question must have 'answers' div,
		 * even if there are currently no answers and the div
		 * is empty.
		 *
		 * This is so that new answer could be added via ajax,
		 * via "answer" form OR when we periodically call server
		 * via ajax to check for new answers we may display a message
		 * like '2 answers... click to load', similar
		 * to Twitter timeline
		 *
		 *
		 *
		 */

		if(!empty($this->answers) && !$this->isLoggedIn()){
			$this->answers = Badwords::filter($this->answers, true);
		}

		return $this;
	}


	/**
	 * Set similars:
	 * similar questions block in
	 * right column
	 *
	 * @return object $this
	 */
	protected function setSimilar(){

		if(!empty($this->aQuestion['sim_q'])){
			$sim = \tplBoxrecent::parse(array($this->_('Similar questions'), 'recent-tags', $this->aQuestion['sim_q']), false);
			$this->aPageVars['tags'] = $sim;
		}

		return $this;
	}


	/**
	 * Add 'Answer' form to template's body
	 *
	 * @return object $this
	 */
	protected function setAnswerForm(){

		$this->aPageVars['body'] .= $this->oForm->getAnswerForm($this->oQuestion);

		return $this;
	}


	/**
	 * Sets the $this->oForm object
	 * We use it to get html of answer form (or empty
	 * string if question is closed to new answers)
	 *
	 * Also in sub-class wwwAnswer we use it for
	 * parsing submitted answer form
	 *
	 * @return object $this
	 */
	protected function makeForm(){
		$this->oForm = Answerform::factory($this->oRegistry);
		$this->oForm->socials = SocialCheckboxes::get($this->oRegistry);

		return $this;
	}


	/**
	 * Adds small extra text to the bottom of
	 * answer form.
	 *
	 * @todo translate text
	 *
	 * @return object $this
	 */
	protected function setFooter(){

		if($this->oQuestion['i_ans'] > 0){
			$text = 'Explore other questions tagged %1$s or <a href="/ask/">ask your own question</a>';
		} else {
			$text = '';
		}

		return $this;
	}


	/**
	 * Must check if current user has already viewed this question,
	 * if not then update QUESTIONS_VIEWS per user collection
	 * and call increaseViews() on oQuestion
	 *
	 * For not-logged-in users use some other method like
	 * checking ip address or maybe just per-session
	 * Like use session_id() value in per user views
	 *
	 * This way even if user not logged in, then loggs in
	 * the view will still count only once!
	 *
	 */
	protected function increaseView(){
		$this->oQuestion->increaseViews($this->oRegistry->Viewer);

		return $this;
	}
	
	//hoangto
	protected function checkGainOtherBadges(){
		
		$cond = $this->oRegistry->Mongo->BADGES->find(array('cond_type' => 'a_question_view_over', 'cond' => array('$lte' => $this->aQuestion['i_views'])));

		foreach($cond as $obj){
			$actData = array(
				'i_uid' => $this->aQuestion['i_uid'],
				'username' => $this->aQuestion['username'],
				'i_bid' => $obj['id'],
				'badges' => $obj['b_name'],
				'badges_type' => $obj['type']
			);
			$isExist = $this->oRegistry->Mongo->USER_BADGES->findOne($actData);
			if(empty($isExist)){
				$this->oRegistry->Mongo->USER_BADGES->insert($actData);
				$this->makeActivities('badges', 'earned a badges', $obj['id'], $a['i_uid']);
			}
			$this->oRegistry->Mongo->USER_BADGES->ensureIndex(array('i_uid' => 1));
			$this->oRegistry->Mongo->USER_BADGES->ensureIndex(array('badges' => 1));
		}
		
		return $this;
	}


	protected function makeTopTabs(){
                $guest = null;
                if($this->oRegistry->Viewer->isGuest()) {
                    $guest['link_ask'] = '#'; // 13
                    $guest['link_ask_click'] = ' onclick="oSL.getQuickRegForm()"'; //14
                }
		$tabs = Urhere::factory($this->oRegistry)->get('tplToptabs', 'questions', $guest);
		$this->aPageVars['topTabs'] = $tabs;

		return $this;
	}
	
	protected function makeFiltertab(){

		$tabs = Urhere::factory($this->oRegistry)->get('tplFiltertabs', $this->qtab);
		$this->aPageVars['filterTabs'] = $tabs;

		return $this;
	}


	/**
	 * Makes the button to "Follow" or "Following"
	 * for this question and sets this html as value
	 * of $this->aPageVars['side']
	 *
	 * @return object $this
	 */
	protected function makeFollowButton(){

		$qid = $this->oQuestion->getResourceId();

		$aVars = array(
                    'id' => $qid,
                    'icon' => 'cplus',
                    'label' => $this->_('Follow this question'),
                    'class' => 'follow',
                    'type' => 'q',
                    'title' => $this->_('Follow this question to be notified of new answers, comments and edits')
		);


		if(in_array($this->oRegistry->Viewer->getUid(), $this->oQuestion['a_flwrs'])){
                    $aVars['label'] = $this->_('Following');
                    $aVars['class'] = 'following';
                    $aVars['icon'] = 'check';
                    $aVars['title'] = $this->_('You are following this question');
		}

		$html = '<div class="cb pl10"><div class="follow_wrap">'.\tplFollowButton::parse($aVars, false).'</div></div>';

		return $html;
	}
	//hoangto tutor listing
	protected function makeTutorListing(){

		$s = $this->getSortedTutors();
		$tutors = \tplTutorBox::parse(array('tutors' => $s, 'title' => $this->_('Tutor Listing')));
		d('cp');
		$this->aPageVars['tutors'] = $tutors;

		return $this;
	}
	
	//hoangto tutor listing loop
	protected function getSortedTutors() {
		
		$cur = $this->oRegistry->Mongo->USERS->find(array('tmp_role' => 'tutor'))->sort(array('experience' => -1))->limit(9);

		$canTeach = '';
		
		$func = function(&$a) use($canTeach){
			$a['canTeach'] = $canTeach;
		};
		
		$tutors = \tplTutorListing::loop($cur, true, $func);
		
		return $tutors;
	}
	
	//hoangto tutor listing
	protected function makeRecentActivites(){

		$s = $this->getSortedActivities();
		$tutors = \tplActivityBox::parse(array('ractivites' => $s, 'title' => $this->_('Recent activities')));
		d('cp');
		$this->aPageVars['activities'] = $tutors;

		return $this;
	}
	
	//hoangto tutor listing loop
	protected function getSortedActivities() {
	
		$act_link = '';
		
		$func = function(&$a) use($act_link){
			$a['act_link'] = $act_link;
		};
		
		$cur = $this->oRegistry->Mongo->ACTIVITIES->find()->sort(array('i_ts' => -1))->limit(5);
			
		$tutors = \tplActivityList::loop($cur, true, $func);
		
		return $tutors;
	}
	
	protected function makeRecentTags(){

		$aUserTags = $this->oRegistry->Viewer['a_f_t'];
		if(!empty($aUserTags)){
			$s = $this->getSortedRecentTags($aUserTags);
		} else {
			$s = $this->oRegistry->Cache->get('qrecent');
		}

		$tags = \tplBoxrecent::parse(array('tags' => $s, 'title' => $this->_('Recent Tags')));
		d('cp');
		$this->aPageVars['tags'] = $tags;

		return $this;
	}
	
	protected function getSortedRecentTags(array $aUserTags, $type = 'recent'){

		$limit = 9;
		if('unanswered' === $type){
			$cur = $this->oRegistry->Mongo->UNANSWERED_TAGS->find(array(), array('tag', 'i_count'))->sort(array('i_ts' => -1))->limit($limit);
		} else {
			$cur = $this->oRegistry->Mongo->QUESTION_TAGS->find(array('i_count' => array('$gt' => 0)), array('tag', 'i_count'))->sort(array('i_ts' => -1))->limit($limit);
		}

		d('got '.$cur->count(true).' tag results');
		$aTags = iterator_to_array($cur);

		d('aTags: '.print_r($aTags, 1));

		if(!empty($aTags)){
			usort($aTags, function($a, $b) use ($aUserTags){
				return (in_array($a['tag'], $aUserTags)) ? -1 : 1;
			});
		};

		d('$aTags now: '.print_r($aTags, 1));
		$html = ('unanswered' === $type) ? \tplUnanstags::loop($aTags) : \tplLinktag::loop($aTags);

		d('html recent tags: '.$html);

		return '<div class="tag"><ul>'.$html.'</ul></div>';
	}

}
